 /**
 * DISCLIMER: 
 * this library is an opensource, feel free to edit or redistribute it
 * but use it with you own risk
 * 
 * ktutnik
 */
package org.ticlib.task
{
	import flash.events.Event;
	
	import mx.core.IMXMLObject;
	import mx.rpc.events.FaultEvent;
	
	[DefaultProperty("tasks")]
	public class MultiTask extends Task implements IMXMLObject
	{
		[ArrayElementType("org.ticlib.task.Task")]
		[Bindable] public var tasks:Array;
		[Bindable] public var continueOnFault:Boolean;
		
		[Bindable] protected var executedCount:uint = 0;
		[Bindable] protected var cancelCount:uint = 0;
		
		public function MultiTask()
		{
			super();
			tasks = new Array();
		}
		
		override public function execute():void{
			super.execute();
			executedCount = 0;
		}
		
		override public function stop():void
		{
			super.stop();
			
			if(!isCanceled)
			{
				for each(var task:Task in tasks)
				{
					task.stop();
					task.isCanceled = true;
				}
				isCanceled = true;
			}
			if((chain) && (!chain.isCanceled))
				chain.stop();
			dispatchEvent(new Event(Event.CANCEL));
		}
		
		public function addTask(task:Task):MultiTask
		{
			task.parent = this;
			task.addEventListener(Event.COMPLETE, onTaskComplete);
			task.addEventListener(FaultEvent.FAULT, onTaskFault);
			task.addEventListener(Event.CANCEL, onTaskCancel);
			tasks.push(task);
			return this;
		}
		
		public function initialized(document:Object, id:String):void
		{
			configureTasks();
		}
		
		/**
		 * abstract
		 * */
		protected function executeNext():void
		{
			
		}
		
		protected function configureTasks():void
		{
			continueOnFault = false;
			for each(var task:Task in tasks)
			{
				task.parent = this;
				task.addEventListener(Event.COMPLETE, onTaskComplete);
				task.addEventListener(FaultEvent.FAULT, onTaskFault);
			}
		}
		
		protected function onTaskComplete(e:Event):void
		{
			executedCount++;
			this.resultObject = (e.target as Task).resultObject;
			if(executedCount == tasks.length)
			{
				isComplete = true;
				dispatchEvent(new Event(Event.COMPLETE));
				if(chain == null) return;
				if(parent == null){
					chain.execute();
					return;
				}
				if(!parent.isComplete)
					chain.execute();
			}
			else
				executeNext();
		}
		
		protected function onTaskFault(e:FaultEvent):void
		{
			executedCount++;
			this.faultObject = (e.target as Task).faultObject;
			if((continueOnFault) && (executedCount <= tasks.length))
				executeNext();
			else
			{
				stop();
				dispatchEvent(FaultEvent.createEvent(e.fault));
			}
		}
		
		protected function onTaskCancel(e:Event):void
		{
			cancelCount++;
			if(cancelCount == tasks.length)
				dispatchEvent(new Event(Event.CANCEL));
		}
	}
}